📅 今日打卡任务 🔥 连续 0

✨ 每天完成1次打卡,赚积分奖励!

✨ AI挑战任务 500元现金
🎨 今日挑战:拍出食物的"灵魂"照片 找一个特别的拍摄角度,让你的食物仿佛在"说话",完成后获得额外奖金加成!
avatar 分享今天的美食,赚积分奖励~ 发布
🏆 AI 美食挑战赛
每周一期,主题美食挑战赛
用照片展示你的美食创意,赢取现金大奖!
💰 奖金池:¥ 500

🔥 热门话题

💎 积分赚取攻略

👤 我的主页
饭桶圈用户
加入于 2026年4月
0
发布
0
获赞
0
粉丝
💰 我的现金
我的积分
📅 打卡日历
📋 我的任务
我的收藏
⚙️ 设置
🚪 退出登录
🎯 发布自定义任务

设置赏金金额,系统自动分配给完成任务的真实用户。
全额发放,平台0服务费

💡 实际到账用户:¥10.00(平台0服务费,全额发放)
drink: { emoji: '🥤', name: '饮料', reward: 8 }, }; const MEAL_TYPES = [ { key: 'all', label: '全部', emoji: '' }, { key: 'breakfast', label: '🌅早餐', emoji: '🌅' }, { key: 'lunch', label: '☀️午餐', emoji: '☀️' }, { key: 'dinner', label: '🌙晚餐', emoji: '🌙' }, { key: 'midnight', label: '🌃夜宵', emoji: '🌃' }, { key: 'drink', label: '🥤饮料', emoji: '🥤' }, ]; // ==================== Sample Posts ==================== const SAMPLE_POSTS = [ { id: 1, userName: '美食探险家', userAvatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Felix', mealType: 'breakfast', mealEmoji: '🌅', text: '今天的早餐超级满足!牛油果吐司配上一杯手冲咖啡,开启美好的一天~ #早餐美学 #咖啡时光', image: 'https://images.unsplash.com/photo-1525351484163-7529414344d8?w=600&q=80', tags: ['#早餐美学', '#咖啡时光'], likes: 234, comments: 45, time: '2小时前', liked: false, points: 10 }, { id: 2, userName: '甜品小当家', userAvatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Luna', mealType: 'lunch', mealEmoji: '☀️', text: '周末约上闺蜜一起吃火锅,辣的过瘾!🥘 #家乡味道 #周末美食', image: 'https://images.unsplash.com/photo-1588166524941-3bf61a9c41db?w=600&q=80', tags: ['#家乡味道', '#周末美食'], likes: 567, comments: 89, time: '4小时前', liked: true, points: 10 }, { id: 3, userName: '厨神养成中', userAvatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Milo', mealType: 'dinner', mealEmoji: '🌙', text: '自己做的红烧肉,色香味俱全!秘诀是多放冰糖~ #家常菜 #下饭神器', image: 'https://images.unsplash.com/photo-1623689046286-6776e8b9e526?w=600&q=80', tags: ['#家常菜', '#下饭神器'], likes: 892, comments: 156, time: '6小时前', liked: false, points: 10 }, { id: 4, userName: '减脂餐分享', userAvatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Sophie', mealType: 'lunch', mealEmoji: '☀️', text: '今日减脂餐:水煮鸡胸肉配西兰花,清爽可口! #减脂餐打卡 #健康饮食', image: 'https://images.unsplash.com/photo-1546069901-ba9599a7e63c?w=600&q=80', tags: ['#减脂餐打卡', '#健康饮食'], likes: 345, comments: 67, time: '8小时前', liked: false, points: 10 }, { id: 5, userName: '深夜食堂主理', userAvatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Noah', mealType: 'midnight', mealEmoji: '🌃', text: '加班到深夜,来一碗热腾腾的泡面,加个蛋,感觉整个人都治愈了~ #深夜食堂 #泡面爱好者', image: 'https://images.unsplash.com/photo-1569718212165-3a8278d5f624?w=600&q=80', tags: ['#深夜食堂', '#泡面爱好者'], likes: 1234, comments: 234, time: '12小时前', liked: true, points: 15 }, ]; const AI_TASKS = [ { title: '🎨 今日挑战:拍出食物的"灵魂"照片', desc: '找一个特别的拍摄角度,让你的食物仿佛在"说话",完成后获得额外奖金加成!', pool: 500 }, { title: '🌈 色彩搭配:三种颜色的食材创作摆盘', desc: '发挥你的艺术天赋,让美食变成一幅画!用色彩讲述你的美食故事。', pool: 300 }, { title: '🍜 童年回忆杀:复刻一道小时候最爱的菜', desc: '用美食重温童年的美好味道~ 用照片记录那道菜背后的故事。', pool: 400 }, { title: '📷 一人食美学:拍出孤独又精致的晚餐', desc: '一个人也要好好吃饭,展现独居生活的仪式感!', pool: 350 }, ]; const EARN_CARDS = [ { icon: '🌅', title: '早餐打卡', sub: '每天6:00-10:00', desc: '拍摄并发布早餐照片,完成打卡任务,即时可获得积分奖励。', reward: '+10积分' }, { icon: '☀️', title: '午餐打卡', sub: '每天11:00-14:00', desc: '记录午餐时光,分享你今天吃了什么,和社区一起发现美食。', reward: '+10积分' }, { icon: '🌙', title: '晚餐打卡', sub: '每天17:00-21:00', desc: '晒出晚餐美食,展示你的生活品质,让更多人感受美食的诱惑。', reward: '+10积分' }, { icon: '🌃', title: '夜宵打卡', sub: '每天21:00-次日2:00', desc: '深夜食堂上线!记录深夜的美食诱惑,夜宵专属额外奖励。', reward: '+15积分' }, { icon: '🥤', title: '饮料打卡', sub: '全天开放', desc: '奶茶、咖啡、果汁...分享你今天的饮品,发现更多宝藏饮品店。', reward: '+8积分' }, { icon: '🏆', title: 'AI挑战赛', sub: '每周更新', desc: '参与AI美食挑战赛,用创意美食照片赢取现金大奖。', reward: '最高500元' }, { icon: '🎯', title: '邀请好友', sub: '长期有效', desc: '每邀请一位好友完成首次发布,双方均可获得积分奖励。', reward: '+20积分' }, { icon: '⭐', title: '每日签到', sub: '每天一次', desc: '每日打开饭桶圈签到,连续签到可获得额外积分加成。', reward: '+5积分' }, ]; const DISCOVER_ITEMS = [ { title: '#减脂餐打卡', img: 'https://images.unsplash.com/photo-1546069901-ba9599a7e63c?w=400&q=80', posts: '2.3万', points: '+10积分/条' }, { title: '#咖啡时光', img: 'https://images.unsplash.com/photo-1509042239860-f550ce710b93?w=400&q=80', posts: '1.8万', points: '+8积分/条' }, { title: '#深夜食堂', img: 'https://images.unsplash.com/photo-1569718212165-3a8278d5f624?w=400&q=80', posts: '3.1万', points: '+15积分/条' }, { title: '#早餐美学', img: 'https://images.unsplash.com/photo-1525351484163-7529414344d8?w=400&q=80', posts: '1.5万', points: '+10积分/条' }, { title: '#家乡味道', img: 'https://images.unsplash.com/photo-1588166524941-3bf61a9c41db?w=400&q=80', posts: '2.7万', points: '+12积分/条' }, { title: '#甜品控', img: 'https://images.unsplash.com/photo-1563729784474-d77dbb933a9e?w=400&q=80', posts: '4.2万', points: '+10积分/条' }, ]; // ==================== Login ==================== async function doLogin() { const nickname = document.getElementById('loginNickname').value.trim(); if (!nickname) { showToast('请输入昵称'); return; } try { const res = await api('POST', '/users/web-login', { nickname }); if (res.code === 0) { currentUser = res.data; state.userId = currentUser.id; state.userName = currentUser.nickname; state.userAvatar = currentUser.avatar || 'https://api.dicebear.com/7.x/avataaars/svg?seed=' + encodeURIComponent(currentUser.nickname); state.isLoggedIn = true; state.balance = currentUser.balance; state.points = currentUser.points; state.streak = currentUser.streakDays || 0; localStorage.setItem('ftq_user', JSON.stringify(currentUser)); document.getElementById('loginModal').classList.remove('show'); await Promise.all([loadPosts(), loadChallenges()]); renderAll(); updateHeader(); showToast('欢迎你,' + currentUser.nickname + '!'); } else { showToast(res.message || '登录失败'); } } catch (e) { showToast('网络错误'); } } function requireLogin() { if (!state.isLoggedIn) { showToast('请先登录'); return false; } return true; } // ==================== Init ==================== async function init() { const savedUser = localStorage.getItem('ftq_user'); if (savedUser) { try { currentUser = JSON.parse(savedUser); state.userId = currentUser.id; state.userName = currentUser.nickname; state.userAvatar = currentUser.avatar || 'https://api.dicebear.com/7.x/avataaars/svg?seed=' + encodeURIComponent(currentUser.nickname); state.isLoggedIn = true; await Promise.all([loadBalance(), loadPoints(), loadPosts(), loadChallenges()]); } catch (e) { localStorage.removeItem('ftq_user'); state.isLoggedIn = false; } } if (!state.isLoggedIn) { document.getElementById('loginModal').classList.add('show'); } renderAll(); initFeedTabs(); initMealTypeSelect(); initChallengePage(); initDiscoverPage(); initEarnPage(); updateHeader(); } async function loadBalance() { if (!state.userId) return; const res = await api('GET', '/balance/info?userId=' + state.userId); if (res.code === 0) { state.balance = res.data.balance; updateHeader(); } } async function loadPoints() { if (!state.userId) return; const res = await api('GET', '/points/info?userId=' + state.userId); if (res.code === 0) { state.points = res.data.points; updateHeader(); } } async function loadPosts() { const mealType = state.activeTab === 'all' ? '' : '&mealType=' + state.activeTab; const res = await api('GET', '/posts/list?page=1&pageSize=50' + mealType); if (res.code === 0) { state.posts = res.data.list.map(p => ({ id: p.id, userName: p.userName, userAvatar: p.userAvatar || 'https://api.dicebear.com/7.x/avataaars/svg?seed=' + encodeURIComponent(p.userName), mealType: p.mealType, mealEmoji: p.mealEmoji, text: p.content, image: p.images && p.images.length > 0 ? p.images[0] : '', tags: p.tags || [], likes: p.likes, comments: p.comments, time: p.time, liked: false, points: p.points })); } } async function loadChallenges() { try { const res = await api('GET', '/challenges/active'); if (res.code === 0 && res.data && res.data.length > 0) { window._apiChallenges = res.data; } } catch (e) {} } function saveState() { if (currentUser) localStorage.setItem('ftq_user', JSON.stringify(currentUser)); } // ==================== Render ==================== function renderAll() { renderMealTasks(); renderFeed(); updateProfile(); } function renderMealTasks() { const container = document.getElementById('mealTasks'); const hint = document.getElementById('taskHint'); const streakEl = document.getElementById('streakCount'); streakEl.textContent = state.streak; if (state.hasCheckedInToday) { hint.textContent = '✅ 今日已打卡!明天再来吧~ 🌟'; hint.className = 'task-hint done'; } else { hint.textContent = '✨ 每天完成1次打卡,赚积分奖励!'; hint.className = 'task-hint'; } container.innerHTML = Object.entries(mealConfig).map(([key, cfg]) => { const done = state.todayTasks[key]; return `
${done ? '' : ''} ${cfg.emoji} ${cfg.name} +${cfg.reward} ${done ? '✓ 已完成' : '→ 去打卡'}
`; }).join(''); } function renderFeed() { const container = document.getElementById('feedList'); const filtered = state.activeTab === 'all' ? state.posts : state.posts.filter(p => p.mealType === state.activeTab); if (filtered.length === 0) { container.innerHTML = `
🍱
暂无内容,快来发布第一篇吧!
`; return; } container.innerHTML = filtered.map(post => `
${post.userName}
${post.image ? `美食图片` : ''}

${post.text}

${post.tags.map(tag => `${tag}`).join('')}
`).join(''); } function updateHeader() { document.getElementById('headerBalance').textContent = state.balance.toFixed(2); document.getElementById('headerPoints').textContent = state.points; } function updateProfile() { const profilePosts = state.posts.filter(p => p.userName === state.userName).length; const totalLikes = state.posts.reduce((sum, p) => p.liked ? sum + p.likes : sum, 0); document.getElementById('profilePosts').textContent = profilePosts; document.getElementById('profileLikes').textContent = totalLikes; document.getElementById('profileFollowers').textContent = '0'; document.getElementById('profileName').textContent = state.userName; document.getElementById('profileAvatar').src = state.userAvatar; } // ==================== Feed Tabs ==================== function initFeedTabs() { const container = document.getElementById('feedTabs'); container.innerHTML = MEAL_TYPES.map(t => ` `).join(''); } async function switchFeedTab(tab) { state.activeTab = tab; document.querySelectorAll('.feed-tab').forEach(btn => { btn.classList.toggle('active', btn.dataset.tab === tab); }); await loadPosts(); renderFeed(); } // ==================== Meal Type Select ==================== function initMealTypeSelect() { const container = document.getElementById('mealTypeSelect'); const types = Object.entries(mealConfig).map(([key, cfg]) => ` `).join(''); container.innerHTML = types; } let selectedMealType = 'lunch'; function selectMealType(type, btn) { selectedMealType = type; document.querySelectorAll('.meal-type-btn').forEach(b => b.classList.remove('selected')); btn.classList.add('selected'); const cfg = mealConfig[type]; document.getElementById('postRewardPoints').textContent = cfg ? cfg.reward : 10; } // ==================== Navigation ==================== function switchPage(page) { document.querySelectorAll('.page-section').forEach(s => s.classList.remove('active')); document.getElementById('page-' + page).classList.add('active'); document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active')); document.querySelector(`.nav-item[data-page="${page}"]`).classList.add('active'); window.scrollTo({ top: 0, behavior: 'smooth' }); } // ==================== Challenge Page ==================== function initChallengePage() { const aiTask = AI_TASKS[Math.floor(Math.random() * AI_TASKS.length)]; document.getElementById('aiTaskTitle').textContent = aiTask.title; document.getElementById('aiTaskDesc').textContent = aiTask.desc; document.getElementById('aiBonus').textContent = aiTask.pool + '元现金'; document.getElementById('poolAmount').textContent = aiTask.pool; const container = document.getElementById('challengeList'); container.innerHTML = AI_TASKS.map((task, i) => `
🏆 ${task.title}
${task.desc}
📋 奖金规则
获奖人数:根据参与人数动态调整
一等奖:奖金池的40%
二等奖:奖金池的30%
三等奖:奖金池的30%
评比标准:照片创意+内容质量
`).join(''); } async function joinChallenge(i) { if (!requireLogin()) return; const btn = document.getElementById('challengeBtn' + i); if (btn.classList.contains('joined')) return; const challenges = window._apiChallenges || AI_TASKS; const challenge = challenges[i]; if (challenge && challenge.id) { try { const res = await api('POST', '/challenges/join', { challengeId: challenge.id, userId: state.userId }); if (res.code === 0) { btn.classList.add('joined'); btn.textContent = '✓ 已参加'; showToast('挑战赛参与成功!'); } else { showToast(res.message || '参与失败'); } } catch (e) { showToast('参与失败'); } } else { btn.classList.add('joined'); btn.textContent = '✓ 已参加'; showToast('挑战赛参与成功!'); } } // ==================== Discover Page ==================== function initDiscoverPage() { const container = document.getElementById('discoverGrid'); container.innerHTML = DISCOVER_ITEMS.map(item => `
${item.title}
${item.title}
${item.posts} 动态
${item.points}
`).join(''); } // ==================== Earn Page ==================== function initEarnPage() { const container = document.getElementById('earnList'); container.innerHTML = EARN_CARDS.map(card => `
${card.icon}
${card.title}
${card.sub}
${card.desc}
${card.reward}
`).join(''); } // ==================== Post Modal ==================== function openPostModal() { document.getElementById('postModal').classList.add('show'); document.getElementById('postText').value = ''; document.getElementById('postImagePreview').style.display = 'none'; selectMealType('lunch', document.querySelector('.meal-type-btn.selected') || document.querySelector('.meal-type-btn[data-type="lunch"]')); document.getElementById('postModalAvatar').src = state.userAvatar; document.getElementById('postModalName').textContent = state.userName; } function closePostModal() { document.getElementById('postModal').classList.remove('show'); } function previewPostImage(input) { if (input.files && input.files[0]) { const reader = new FileReader(); reader.onload = function(e) { document.getElementById('postPreviewImg').src = e.target.result; document.getElementById('postImagePreview').style.display = 'block'; }; reader.readAsDataURL(input.files[0]); } } function removePostImage() { document.getElementById('postImagePreview').style.display = 'none'; document.getElementById('postImagePreview').querySelector('img').src = ''; document.getElementById('postImageUpload').querySelector('input').value = ''; } async function submitPost() { if (!requireLogin()) return; const text = document.getElementById('postText').value.trim(); const previewImg = document.getElementById('postPreviewImg').src; const hasImage = previewImg && !previewImg.includes('data:,'); if (!text) { showToast('请输入内容'); return; } if (text.length < 3) { showToast('内容太短了,至少输入3个字符'); return; } const cfg = mealConfig[selectedMealType] || mealConfig.lunch; try { const res = await api('POST', '/posts/publish', { userId: state.userId, content: text, images: hasImage ? [previewImg] : [], tags: extractTags(text), mealType: selectedMealType }); if (res.code === 0) { closePostModal(); showToast('发布成功!获得 +' + (res.data.pointsEarned || cfg.reward) + ' 积分'); state.todayTasks[selectedMealType] = true; renderMealTasks(); await Promise.all([loadPosts(), loadPoints()]); renderFeed(); } else { showToast(res.message || '发布失败'); } } catch (e) { showToast('网络错误,发布失败'); } } function extractTags(text) { const matches = text.match(/#[\u4e00-\u9fa5a-zA-Z0-9]+/g); return matches ? matches.slice(0, 3) : []; } // ==================== Profile Modal ==================== function openProfile() { document.getElementById('profileModal').classList.add('show'); document.getElementById('profileModalAvatar').src = state.userAvatar; document.getElementById('profileModalName').textContent = state.userName; } function closeProfileModal() { document.getElementById('profileModal').classList.remove('show'); } // Alias for header avatar function openProfileModal() { openProfile(); } // ==================== Wallet Modal ==================== let walletMode = 'balance'; async function openWallet() { if (!requireLogin()) return; walletMode = 'balance'; document.getElementById('walletTitle').textContent = '💰 我的现金'; document.getElementById('walletBalanceLabel').textContent = '可提现余额'; document.getElementById('walletBalance').textContent = state.balance.toFixed(2); document.getElementById('walletTodayEarn').textContent = ''; try { const res = await api('GET', '/balance/logs?userId=' + state.userId + '&pageSize=20'); const container = document.getElementById('balanceRecords'); if (res.code === 0 && res.data.list.length > 0) { container.innerHTML = res.data.list.map(log => `
${log.reason}
${log.time}
${log.amount >= 0 ? '+' : ''}${log.amount.toFixed(2)}
`).join(''); } else { container.innerHTML = '
暂无记录
'; } } catch (e) { document.getElementById('balanceRecords').innerHTML = '
加载失败
'; } document.getElementById('walletModal').classList.add('show'); closeProfileModal(); } function closeWalletModal() { document.getElementById('walletModal').classList.remove('show'); } function withdrawBalance() { if (state.balance < 1) { showToast('余额不足1元,无法提现'); return; } showToast(`提现申请已提交 ¥${state.balance.toFixed(2)}(功能演示中)`); } // ==================== Interactions ==================== async function toggleLike(postId) { if (!requireLogin()) return; try { const res = await api('POST', '/posts/like', { postId, userId: state.userId }); if (res.code === 0) { const post = state.posts.find(p => p.id === postId); if (post) { post.liked = res.data.liked; post.likes += res.data.liked ? 1 : -1; renderFeed(); } } } catch (e) { showToast('操作失败'); } } async function showComment(postId) { if (!requireLogin()) return; const comment = prompt('写下你的评论:'); if (comment && comment.trim()) { try { const res = await api('POST', '/posts/comment', { postId, userId: state.userId, content: comment.trim() }); if (res.code === 0) { const post = state.posts.find(p => p.id === postId); if (post) { post.comments++; renderFeed(); } showToast('评论成功!'); } else { showToast(res.message || '评论失败'); } } catch (e) { showToast('评论失败'); } } } function sharePost(postId) { if (navigator.share) { navigator.share({ title: '饭桶圈 - 分享你的美食生活', text: '发现超棒的美食,快来看看!', url: window.location.href }); } else { navigator.clipboard.writeText(window.location.href).then(() => { showToast('链接已复制,快去分享吧!🔗'); }); } } function onAcceptTask() { if (!requireLogin()) return; showToast('已接受任务!完成任务可获得额外奖励 ✨'); } function onMealTask(meal) { if (!requireLogin()) return; if (state.todayTasks[meal]) { showToast('该任务已完成 ✓'); return; } selectedMealType = meal; openPostModal(); } function updateTaskFee() { const bounty = parseFloat(document.getElementById('taskBountyInput').value) || 0; const actual = bounty.toFixed(2); document.getElementById('taskActualAmount').textContent = '¥' + actual; } function submitTask() { const title = document.getElementById('taskTitleInput').value.trim(); const desc = document.getElementById('taskDescInput').value.trim(); const bounty = parseFloat(document.getElementById('taskBountyInput').value) || 0; const quota = parseInt(document.getElementById('taskQuotaInput').value) || 1; if (!title) { showToast('请输入任务标题'); return; } if (!desc) { showToast('请输入任务描述'); return; } if (bounty < 1) { showToast('赏金至少1元'); return; } if (state.balance < bounty) { showToast('余额不足,请先充值'); return; } deductBalance(bounty, `发布任务:${title}`); updateHeader(); showToast(`任务发布成功!赏金 ¥${bounty.toFixed(2)} 已预扣`); document.getElementById('taskTitleInput').value = ''; document.getElementById('taskDescInput').value = ''; document.getElementById('taskBountyInput').value = '10'; document.getElementById('taskQuotaInput').value = '1'; updateTaskFee(); } // ==================== Balance & Points (API) ==================== // 余额和积分变动现在通过后端API完成,这里只保留读取功能 // ==================== Toast ==================== function showToast(msg) { const toast = document.getElementById('toast'); toast.textContent = msg; toast.classList.add('show'); setTimeout(() => toast.classList.remove('show'), 2500); } // ==================== Keyboard shortcuts ==================== document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { closePostModal(); closeProfileModal(); closeWalletModal(); } }); // ==================== Close modals on overlay click ==================== document.querySelectorAll('.modal-overlay').forEach(overlay => { overlay.addEventListener('click', (e) => { if (e.target === overlay) { overlay.classList.remove('show'); } }); }); // ==================== Search ==================== document.getElementById('searchInput').addEventListener('keydown', (e) => { if (e.key === 'Enter') { const q = e.target.value.trim(); if (q) { showToast(`搜索"${q}"功能暂未开放`); } } }); // ==================== Start ==================== init();